You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

244 lines
8.7 KiB

"use client";
import Link from "next/link";
import { useRouter } from "next/navigation";
import { useEffect, useMemo, useState } from "react";
import {
countCompletedDetailedAnswers,
detailedSections,
type DetailedSection,
getDetailedQuestionCount,
getDetailedSectionProgress,
getDetailedSectionStorageKey,
} from "@/lib/detailed-questions";
function BackIcon() {
return (
<svg
aria-hidden="true"
fill="none"
height="18"
viewBox="0 0 18 18"
width="18"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M10.5 4.5 6 9l4.5 4.5"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.8"
/>
</svg>
);
}
export default function DetailSectionClient({
section,
}: {
section: DetailedSection;
}) {
const [answers, setAnswers] = useState<Record<string, string>>({});
const [isHydrated, setIsHydrated] = useState(false);
const router = useRouter();
useEffect(() => {
const savedAnswers = window.localStorage.getItem(
getDetailedSectionStorageKey(section.id),
);
setAnswers(
savedAnswers ? (JSON.parse(savedAnswers) as Record<string, string>) : {},
);
setIsHydrated(true);
}, [section.id]);
useEffect(() => {
if (!isHydrated) {
return;
}
window.localStorage.setItem(
getDetailedSectionStorageKey(section.id),
JSON.stringify(answers),
);
const completedTotal = detailedSections.reduce((total, currentSection) => {
const sectionAnswers =
currentSection.id === section.id
? answers
: ((JSON.parse(
window.localStorage.getItem(
getDetailedSectionStorageKey(currentSection.id),
) ?? "{}",
) as Record<string, string>) ?? {});
return (
total + countCompletedDetailedAnswers(currentSection, sectionAnswers)
);
}, 0);
if (completedTotal === getDetailedQuestionCount()) {
router.replace("/details/complete");
}
}, [answers, isHydrated, router, section, section.id]);
const completedCount = useMemo(
() => countCompletedDetailedAnswers(section, answers),
[answers, section],
);
const progress = useMemo(
() => getDetailedSectionProgress(section, answers),
[answers, section],
);
const handleChange = (questionId: string, value: string) => {
setAnswers((currentAnswers) => ({
...currentAnswers,
[questionId]: value,
}));
};
return (
<main className="flex min-h-screen items-center justify-center bg-[#444446] p-2 sm:p-4">
<section className="relative aspect-[375/813] w-full max-w-[375px] overflow-hidden rounded-[24px] bg-[#FCF8F7] shadow-[0_30px_70px_rgba(0,0,0,0.34)]">
<div className="absolute inset-0 bg-[radial-gradient(circle_at_top,#FFB8CE_0%,rgba(255,184,206,0.26)_12%,rgba(255,255,255,0)_34%),linear-gradient(180deg,#FFFDFD_0%,#F9F4F6_100%)]" />
<div className="relative z-10 flex h-full flex-col px-4 pb-5 pt-5">
<div className="flex items-center justify-between px-2 text-[#1C1C1E]">
<span className="text-[14px] font-semibold">9:41</span>
<div className="flex items-center gap-1.5">
<span className="block h-[7px] w-[18px] rounded-[3px] border border-current opacity-85" />
<span className="block h-[7px] w-[7px] rounded-full bg-current opacity-85" />
</div>
</div>
<div className="mt-4 flex items-center justify-between">
<Link
aria-label="Back to detailed questions"
className="flex h-11 w-11 items-center justify-center rounded-full bg-white text-[#202020] shadow-[0_10px_24px_rgba(0,0,0,0.08)]"
href="/details"
>
<BackIcon />
</Link>
<h1
className="text-[20px] font-semibold text-[#2A1D1E]"
style={{ fontFamily: "Georgia, Times New Roman, serif" }}
>
{section.title}
</h1>
<span className="w-11 text-right text-[12px] font-semibold text-[#6E656B]">
{progress}%
</span>
</div>
<div className="mt-6 rounded-[26px] bg-white/90 px-5 py-6 shadow-[0_18px_40px_rgba(0,0,0,0.07)]">
<p className="text-[12px] font-semibold uppercase tracking-[0.22em] text-[#F05A93]">
Section Progress
</p>
<h2
className="mt-3 text-[27px] font-semibold leading-[1.15] text-[#2E2327]"
style={{ fontFamily: "Georgia, Times New Roman, serif" }}
>
{section.title}
</h2>
<p className="mt-3 text-[14px] leading-6 text-[#675E64]">
{section.description}
</p>
<div className="mt-5 h-[10px] overflow-hidden rounded-full bg-[#F7D9E4]">
<div
className="h-full rounded-full bg-linear-to-r from-[#F04C99] to-[#FF8575] transition-[width] duration-300"
style={{ width: `${progress}%` }}
/>
</div>
<p className="mt-3 text-[12px] font-medium tracking-[0.04em] text-[#8B8086]">
{completedCount} of {section.questions.length} questions answered
</p>
</div>
<div className="mt-5 flex-1 space-y-4 overflow-y-auto pb-2">
{section.questions.map((question) => {
const value = answers[question.id] ?? "";
return (
<article
className="rounded-[22px] bg-white/92 px-5 py-5 shadow-[0_14px_34px_rgba(0,0,0,0.06)]"
key={question.id}
>
<h3 className="text-[17px] font-semibold leading-7 text-[#31252A]">
{question.label}
</h3>
<p className="mt-2 text-[13px] leading-6 text-[#72686E]">
{question.description}
</p>
<div className="mt-4">
{question.type === "textarea" ? (
<textarea
className="min-h-[132px] w-full resize-none rounded-[18px] border border-[#F3DFE7] bg-[#FFFDFE] px-4 py-3 text-[15px] leading-7 text-[#33292D] outline-none transition focus:border-[#F05A93]"
onChange={(event) =>
handleChange(question.id, event.target.value)
}
placeholder={question.placeholder}
value={value}
/>
) : null}
{question.type === "text" ? (
<input
className="h-[54px] w-full rounded-[18px] border border-[#F3DFE7] bg-[#FFFDFE] px-4 text-[15px] text-[#33292D] outline-none transition focus:border-[#F05A93]"
onChange={(event) =>
handleChange(question.id, event.target.value)
}
placeholder={question.placeholder}
type="text"
value={value}
/>
) : null}
{question.type === "number" ? (
<input
className="h-[54px] w-full rounded-[18px] border border-[#F3DFE7] bg-[#FFFDFE] px-4 text-[15px] text-[#33292D] outline-none transition focus:border-[#F05A93]"
inputMode="numeric"
onChange={(event) =>
handleChange(question.id, event.target.value)
}
placeholder={question.placeholder}
type="number"
value={value}
/>
) : null}
{question.type === "date" ? (
<input
className="h-[54px] w-full rounded-[18px] border border-[#F3DFE7] bg-[#FFFDFE] px-4 text-[15px] text-[#33292D] outline-none transition focus:border-[#F05A93]"
onChange={(event) =>
handleChange(question.id, event.target.value)
}
type="date"
value={value}
/>
) : null}
</div>
</article>
);
})}
</div>
<div className="mt-4">
<Link
className="flex h-[48px] items-center justify-center rounded-[14px] bg-[#242424] text-[18px] font-semibold text-white shadow-[0_14px_30px_rgba(0,0,0,0.18)]"
href="/details"
>
Back To List
</Link>
</div>
</div>
</section>
</main>
);
}